package org.hsqldb.index;

import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.Constraint;
import org.hsqldb.Row;
import org.hsqldb.RowAVL;
import org.hsqldb.RowLinkList;
import org.hsqldb.Session;
import org.hsqldb.Table;
import org.hsqldb.TableBase;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.persist.PersistentStore;
import org.hsqldb.types.Type;

public class IndexLinkListMemory extends IndexLinkList{

	public IndexLinkListMemory(HsqlName name, long id, TableBase table,
			int[] columns, boolean[] descending, boolean[] nullsLast,
			Type[] colTypes, boolean pk, boolean unique, boolean constraint,
			boolean forward) {
		super(name, id, table, columns, descending, nullsLast, colTypes, pk, unique,
				constraint, forward);
		// TODO Auto-generated constructor stub
	}
	
	

	/**
     * Insert a node into the index
     */
    public void insert(Session session, PersistentStore store, Row row) {
    	writeLock.lock();
    	boolean compareRowId = !isUnique || hasNulls(session, row.getData());
    	
    	try {
			NodeLinkList head = (NodeLinkList)getAccessor(store);
			if(head == null){
				store.setAccessor(this, ( (RowLinkList)row).getNode(position));
				return;
			}
			NodeLinkList current = head,pre = null;
			int compare = -1;
			//boolean isLeft = false;
			while(true){
				Row currentRow = current.getRow(store);
				compare = compareRowForInsertOrDelete(session, row, currentRow, compareRowId, 0);

                if (compare == 0) {
                    Constraint c = null;

                    if (isConstraint) {
                        c = ((Table) table).getUniqueConstraintForIndex(this);
                    }

                    if (c == null) {
                        throw Error.error(ErrorCode.X_23505,
                                          name.statementName);
                    } else {
                        throw c.getException(row.getData());
                    }
                }
                if(compare < 0){
                	//isLeft = true;
                	//pre = current;
                	break;
                }
                else{
                	pre = current;
                	current = current.getNext(store);
                }
                if(current == null){
                	//isLeft = false;
                	break;
                }	
			}
			
			NodeLinkList newNode = ((RowLinkList)row).getNode(position);
			if(current == null){
				pre.setNext(store, newNode);
				newNode.setPre(store, pre);;
			}
			else{
				if(pre != null){
					pre.setNext(store, newNode);
					newNode.setPre(store, pre);
					newNode.setNext(store,current);
					current.setPre(store,newNode);
				}
				else{
					current.setPre(store,newNode);
					newNode.setNext(store,current);
					newNode.setPre(store, null);// = null;
					store.setAccessor(this, newNode);
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
    	finally{
    		writeLock.unlock();
    	}
    }
    
    public void delete(Session session, PersistentStore store, Row row) {
        if (!row.isInMemory()) {
            row = (Row) store.get(row, false);
        }

        NodeLinkList node = ((RowLinkList) row).getNode(position);

        if (node != null) {
            delete(store, node);
        }
    }
    void delete(PersistentStore store, NodeLinkList x){
        if (x == null) {
            return;
        }

        writeLock.lock();
        try{
        	if(x.getPre(store)==null){
        		if(x.getNext(store) != null){
        			NodeLinkList d=x.getNext(store);
        			d.setPre(store, null);
        			store.setAccessor(this, d);		
        		}
        		else{
        			store.setAccessor(this, null);
        		}
        		x.delete();
        	}
        	else if(x.getNext(store)==null){
        		x.getPre(store).setNext(store, null);
        		x.delete();
        	}
        	else{
        		NodeLinkList p=x.getPre(store);
        		NodeLinkList n=x.getNext(store);
        		p.setNext(store,n);
        		n.setPre(store, p);
        		x.delete();
        	}
        	
    	} finally {
    		writeLock.unlock();
    	}
    }
    private NodeLinkList next(Session session, PersistentStore store, NodeLinkList nextnode, int distinctCount){
		return nextnode.getNext(store);
	}
	
	private NodeLinkList last(Session session, PersistentStore store, NodeLinkList nextnode, int distinctCount){
		return nextnode.getNext(store);
	}

}
